package com.learn.criminalintent

import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.net.Uri
import android.os.Bundle
import android.provider.ContactsContract
import android.provider.MediaStore
import android.text.Editable
import android.text.TextWatcher
import android.text.format.DateFormat
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.Button
import android.widget.CheckBox
import android.widget.EditText
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import java.io.File
import java.util.Calendar
import java.util.Date
import java.util.UUID


private const val TAG = "CrimeFragment"

private const val ARG_CRIME_ID = "crime_id"

private const val DIALOG_DATE = "DialogDate"

private const val REQUEST_DATE = 0

private const val REQUEST_CONTACT = 1

private const val REQUEST_PHONE = 2

private const val REQUEST_PHOTO = 3

private const val DATE_FORMAT = "EEE, MMM, dd"

class CrimeFragment : Fragment(), DatePickerFragment.CallBacks, TimePickerFragment.CallBacks {

    private lateinit var crime: Crime
    private lateinit var photoFile: File
    private lateinit var photoUri: Uri
    private lateinit var photoView: ImageView
    private lateinit var photoButton: ImageButton
    private lateinit var titleField: EditText
    private lateinit var dateButton: Button
    private lateinit var timeButton: Button
    private lateinit var solvedCheckBox: CheckBox
    private lateinit var crimeSuspectButton: Button
    private lateinit var crimeReportButton: Button
    private lateinit var crimeCallSuspectButton: Button
    private var viewWidth = 0
    private var viewHeight = 0

    private val crimeDetailViewModel: CrimeDetailViewModel by lazy {
        ViewModelProviders.of(this).get(CrimeDetailViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "onCreate() called")

        crime = Crime()
        val crimeId: UUID = arguments?.getSerializable(ARG_CRIME_ID) as UUID
        Log.d(TAG, "args bundle crime ID: $crimeId")

        crimeDetailViewModel.loadCrime(crimeId)
    }

    /**
     * 该函数会实例化fragment视图的布局，然后将实例化的View返回给托管activity。
     */
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        Log.d(TAG, "onCreateView() called")
        // fragment的视图是直接通过调用LayoutInflater.inflate(...)函数并传入布局的资源ID生成的。
        // 第二个参数是视图的父视图，我们通常需要父视图来正确配置部件。
        // 第三个参数告诉布局生成器是否立即将生成的视图添加给父视图。
        // 这里传入了false参数，因为fragment的视图将由activity的容器视图托管。稍后，activity会处理。
        val view = inflater.inflate(R.layout.fragment_crime, container, false)

        // 在fragment中实例化部件
        photoView = view.findViewById(R.id.crime_photo) as ImageView
        photoButton = view.findViewById(R.id.crime_camera) as ImageButton
        titleField = view.findViewById(R.id.crime_title) as EditText
        dateButton = view.findViewById(R.id.crime_date) as Button
        timeButton = view.findViewById(R.id.crime_time) as Button
        solvedCheckBox = view.findViewById(R.id.crime_solved) as CheckBox
        crimeSuspectButton = view.findViewById(R.id.crime_suspect) as Button
        crimeReportButton = view.findViewById(R.id.crime_report) as Button
        crimeCallSuspectButton = view.findViewById(R.id.call_suspect) as Button

        photoView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                Log.d(TAG, "onGlobalLayout() called")
                viewWidth = photoView.width
                viewHeight = photoView.height
            }
        })

        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        Log.d(TAG, "onViewCreated() called")

        // 观察CrimeDetailViewModel的crimeLiveData，一有新数据发布就更新UI
        crimeDetailViewModel.crimeLiveData.observe(
            viewLifecycleOwner,
            Observer { crime ->
                crime?.let {
                    this.crime = crime
                    photoFile = crimeDetailViewModel.getPhotoFile(crime)

                    // FileProvider.getUriForFile 把本地文件路径转换为相机能使用的Uri形式
                    // 传给FileProvider.getUriForFile(...)的授权字符串要和manifest文件里的相匹配
                    photoUri = FileProvider.getUriForFile(
                        requireActivity(),
                        "com.learn.criminalintent.fileprovider",
                        photoFile
                    )
                    updateUI()
                }
            }
        )
    }

    override fun onStart() {
        super.onStart()
        Log.d(TAG, "onStart() called")

        val titleWatcher = object : TextWatcher {
            override fun beforeTextChanged(
                sequence: CharSequence?,
                start: Int,
                count: Int,
                after: Int
            ) {
                // 这个方法在文本改变之前被调用
            }

            override fun onTextChanged(
                sequence: CharSequence?,
                start: Int,
                before: Int,
                count: Int
            ) {
                crime.title = sequence.toString()
            }

            override fun afterTextChanged(sequence: Editable?) {
                // 这个方法在文本改变之后被调用
            }
        }
        titleField.addTextChangedListener(titleWatcher)


//        solvedCheckBox.setOnCheckedChangeListener { _, isChecked ->
//            crime.isSolved = isChecked
//        }
        // 等同上面的代码
        solvedCheckBox.apply {
            setOnCheckedChangeListener { _, isChecked ->
                crime.isSolved = isChecked
            }
        }

        dateButton.setOnClickListener {
            // 创建对象、传递参数、并打开日期选择框
            DatePickerFragment.newInstance(crime.date).apply {
                setTargetFragment(this@CrimeFragment, REQUEST_DATE)
                show(this@CrimeFragment.requireFragmentManager(), DIALOG_DATE)
            }
        }

        timeButton.setOnClickListener {
            TimePickerFragment.newInstance(crime.date).apply {
                setTargetFragment(this@CrimeFragment, REQUEST_DATE)
                show(this@CrimeFragment.requireFragmentManager(), DIALOG_DATE)
            }
        }

        crimeSuspectButton.apply {
            val pickContactIntent =
                Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
            setOnClickListener {
                startActivityForResult(pickContactIntent, REQUEST_CONTACT)
            }

            // 测试下面的功能，模式按钮被禁用
            // pickContactIntent.addCategory(Intent.CATEGORY_HOME)

            // 检查是否存在联系人应用，如果不存在则禁用按钮
            val packageManager: PackageManager = requireActivity().packageManager
            val resolveActivity: ResolveInfo? =
                packageManager.resolveActivity(pickContactIntent, PackageManager.MATCH_DEFAULT_ONLY)
            if (resolveActivity == null) {
                Log.w(TAG, "No contacts app found on device")
                isEnabled = false
            }
        }

        crimeReportButton.setOnClickListener {
            // 创建一个隐式intent并传入startActivity(Intent)函数
            Intent(Intent.ACTION_SEND).apply {
                type = "text/plain"
                putExtra(Intent.EXTRA_TEXT, getCrimeReport())
                putExtra(Intent.EXTRA_SUBJECT, getString(R.string.crime_report_subject))
            }.also { intent ->
                // 方式一：创建一个选择器，让用户选择要使用的应用程序。
//                startActivity(intent)

                // 方式二：创建每次都显示的activity选择器。
                // 在模拟器上无法显示 title，在真机上可以正常显示 title。
                val chooserIntent = Intent.createChooser(intent, getString(R.string.send_report))
                startActivity(chooserIntent)
            }
        }

        crimeCallSuspectButton.apply {
            val pickPhoneIntent =
                Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI)
            setOnClickListener {
                if (crime.phone.isNotBlank()) {
                    callSuspect()
                } else {
                    setOnClickListener {
                        startActivityForResult(pickPhoneIntent, REQUEST_PHONE)
                    }
                }
            }
        }

        photoButton.apply {
            val packageManager: PackageManager = requireActivity().packageManager

            val captureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            val resolveActivity: ResolveInfo? =
                packageManager.resolveActivity(captureIntent, PackageManager.MATCH_DEFAULT_ONLY)

            // TODO 虚拟机会返回null，但是依然可以打开相机
            if (resolveActivity == null) {
                Log.w(TAG, "No camera app found on device")
                Toast.makeText(context, getString(R.string.no_camera_app), Toast.LENGTH_SHORT)
                    .show()
//                isEnabled = false
            }

            setOnClickListener {
                captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri)

                val cameraActivities = packageManager.queryIntentActivities(
                    captureIntent,
                    PackageManager.MATCH_DEFAULT_ONLY
                )

                for (activity in cameraActivities) {
                    requireActivity().grantUriPermission(
                        activity.activityInfo.packageName,
                        photoUri,
                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                    )
                }

                startActivityForResult(captureIntent, REQUEST_PHOTO)
            }
        }
    }

    override fun onStop() {
        super.onStop()
        Log.d(TAG, "onStop() called")
        // 返回到列表界面时保存数据
        crimeDetailViewModel.saveCrime(crime)
    }

    override fun onDetach() {
        super.onDetach()
        requireActivity().revokeUriPermission(
            photoUri,
            Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        )
    }

    /**
     * ，DatePickerFragment 传递过来选中的数据，然后更新界面
     */
    override fun onDateSelected(date: Date) {
        // 更新 crime 的日期
        this.crime.date = mergeDateAndTime(date, crime.date)
        updateUI()
    }

    override fun onTimeSelected(date: Date) {
        // 更新 crime 的时间
        this.crime.date = mergeDateAndTime(crime.date, date)
        updateUI()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        Log.d(TAG, "onActivityResult() called")
        when {
            resultCode != Activity.RESULT_OK -> return
            // 处理联系人选择结果
            requestCode == REQUEST_CONTACT && data != null -> {
                // 从返回的 Intent 中获取联系人的 Uri，如果为空则直接返回
                val contactUri: Uri = data.data ?: return

                // 定义要查询的字段，这里只查询联系人的显示名称
                val queryFields = arrayOf(ContactsContract.Contacts.DISPLAY_NAME)

                // 通过 ContentResolver 查询联系人信息
                val cursor = requireActivity().contentResolver
                    .query(contactUri, queryFields, null, null, null)

                // 使用 use 函数确保 Cursor 在使用完后自动关闭
                cursor?.use {
                    // 如果查询结果为空，直接返回
                    if (it.count == 0) {
                        return
                    }

                    // 将光标移动到第一条记录
                    it.moveToFirst()
                    // 获取联系人的显示名称
                    val suspect = it.getString(0)
                    // 将联系人名称赋值给当前案件的嫌疑人字段
                    crime.suspect = suspect
                    // 保存更新后的案件信息
                    crimeDetailViewModel.saveCrime(crime)
                    crimeSuspectButton.text = suspect
                }
            }

            requestCode == REQUEST_PHONE && data != null -> {
                // 从返回的 Intent 中获取联系人的 Uri，如果为空则直接返回
                val contactUri: Uri = data.data ?: return
                // 定义要查询的字段，这里只查询联系人的显示名称
                val queryFields = arrayOf(ContactsContract.CommonDataKinds.Phone.NUMBER)

                val cursor = requireActivity().contentResolver
                    .query(contactUri, queryFields, null, null, null)
                cursor?.use {
                    // 如果查询结果为空，直接返回
                    if (it.count == 0) {
                        return
                    }

                    // 将光标移动到第一条记录
                    it.moveToFirst()
                    val phone = it.getString(0)
                    Log.d(TAG, "Phone number: $phone")
                    crime.phone = phone
                    crimeDetailViewModel.saveCrime(crime)

                    crimeCallSuspectButton.text = getString(R.string.call_suspect, phone)
                }
            }

            requestCode == REQUEST_PHOTO -> {
                requireActivity().revokeUriPermission(
                    photoUri,
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                )
                updatePhotoView()
            }
        }
    }

    private fun callSuspect() {
        val intent = Intent(Intent.ACTION_DIAL)
        intent.data = Uri.parse("tel:${crime.phone}")
        startActivity(intent)
    }

    private fun updateUI() {
        titleField.setText(crime.title)
        val date = DateFormat.format("yyyy-MM-dd HH:mm:ss EE", crime.date)
        dateButton.text = date
        // 设置CheckBox的选中状态
        // solvedCheckBox.isChecked = crime.isSolved
        // 等同上面的代码, 跳过 checked 状态的动画
        solvedCheckBox.apply {
            isChecked = crime.isSolved
            jumpDrawablesToCurrentState()
        }

        if (crime.suspect.isNotBlank()) {
            crimeSuspectButton.text = crime.suspect
        }

        if (crime.phone.isNotBlank()) {
            crimeCallSuspectButton.text = getString(R.string.call_suspect, crime.phone)
        } else {
            crimeCallSuspectButton.text = getString(R.string.choose_suspect)
        }

        updatePhotoView()
    }

    private fun updatePhotoView() {
        if (photoFile.exists()) {
            val bitmap = getScaledBitmap(photoFile.path, viewWidth, viewHeight)
            photoView.setImageBitmap(bitmap)

            photoView.setOnClickListener {
                val photoViewFragment = PhotoViewFragment.newInstance(photoFile.path)
                fragmentManager?.let { it1 -> photoViewFragment.show(it1, "DialogPicture") }
            }
        } else {
            photoView.setImageBitmap(null)
        }
    }

    private fun getCrimeReport(): String {
        // 是否解决
        val solvedString = if (crime.isSolved) {
            getString(R.string.crime_report_solved)
        } else {
            getString(R.string.crime_report_unsolved)
        }

        // 格式化日期
        val dateString = DateFormat.format(DATE_FORMAT, crime.date).toString()

        // 检查嫌疑人是否为空
        var suspect = if (crime.suspect.isBlank()) {
            getString(R.string.crime_report_no_suspect)
        } else {
            getString(R.string.crime_report_suspect, crime.suspect)
        }

        return getString(
            R.string.crime_report,
            crime.title, dateString, solvedString, suspect
        )
    }

    // 合并两个 Date 对象的日期和时间部分
    private fun mergeDateAndTime(datePart: Date, timePart: Date): Date {
        val dateCalendar = Calendar.getInstance().apply { time = datePart }
        val timeCalendar = Calendar.getInstance().apply { time = timePart }

        return Calendar.getInstance().apply {
            // 设置日期部分
            set(Calendar.YEAR, dateCalendar.get(Calendar.YEAR))
            set(Calendar.MONTH, dateCalendar.get(Calendar.MONTH))
            set(Calendar.DAY_OF_MONTH, dateCalendar.get(Calendar.DAY_OF_MONTH))

            // 设置时间部分
            set(Calendar.HOUR_OF_DAY, timeCalendar.get(Calendar.HOUR_OF_DAY))
            set(Calendar.MINUTE, timeCalendar.get(Calendar.MINUTE))
            set(Calendar.SECOND, timeCalendar.get(Calendar.SECOND))
            set(Calendar.MILLISECOND, timeCalendar.get(Calendar.MILLISECOND))
        }.time
    }

    companion object {
        fun newInstance(crimedId: UUID): CrimeFragment {
            val args = Bundle().apply {
                putSerializable(ARG_CRIME_ID, crimedId)
            }
            return CrimeFragment().apply {
                arguments = args
            }
        }
    }
}